package cn.tm.ms.nerver.ft;

import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import cn.tm.ms.nerver.ft.entry.FtDo;
import cn.tm.ms.nerver.ft.strategy.FtStrategy;
import cn.tm.ms.nerver.ft.strategy.support.Broadcast;
import cn.tm.ms.nerver.ft.strategy.support.Failback;
import cn.tm.ms.nerver.ft.strategy.support.Failcache;
import cn.tm.ms.nerver.ft.strategy.support.Failfast;
import cn.tm.ms.nerver.ft.strategy.support.Failover;
import cn.tm.ms.nerver.ft.strategy.support.Failsafe;
import cn.tm.ms.nerver.ft.strategy.support.Forking;
import cn.tm.ms.nerver.ft.type.FtType;

/**
 * 容错机制模块
 * <p>
 * 1.动态配置容错策略类型<p>
 * 2.动态配置容错参数(线程数、超时时间)<p>
 * 3.动态配置容错次数也间隔<p>
 * 4.动态注入路由模块
 * 
 * @author lry
 *
 * @param <REQ>
 * @param <RES>
 */
public class FtModuler<REQ, RES> {
	
	private ConcurrentHashMap<String, FtStrategy<REQ, RES>> ftStrategyMap;
	
	public FtModuler(){
		ftStrategyMap=new ConcurrentHashMap<String, FtStrategy<REQ, RES>>();
		
		ftStrategyMap.put(FtType.FAILOVER.toString(), new Failover<REQ, RES>());
		ftStrategyMap.put(FtType.FAILFAST.toString(), new Failfast<REQ, RES>());
		ftStrategyMap.put(FtType.FAILSAFE.toString(), new Failsafe<REQ, RES>());
		ftStrategyMap.put(FtType.FAILCACHE.toString(), new Failcache<REQ, RES>());
		ftStrategyMap.put(FtType.FAILBACK.toString(), new Failback<REQ, RES>());
		ftStrategyMap.put(FtType.FORKING.toString(), new Forking<REQ, RES>());
		ftStrategyMap.put(FtType.BROADCAST.toString(), new Broadcast<REQ, RES>());
	}
	
	/**
	 * 执行
	 * 
	 * @param ftType
	 * @param ftDo
	 * @return
	 */
	public RES execute(String ftType, FtDo<REQ, RES> ftDo) {
		if(ftDo==null){
			throw new RuntimeException("'ftDo' cannot be empty.");
		}
		
		//放通率校验
		if(new Random().nextDouble()>ftDo.getConf().getPassRate()){
			throw new RuntimeException("Refused to put through.");
		}
		
		FtStrategy<REQ, RES> ftStrategy=ftStrategyMap.get(ftType.toString());
		if(ftStrategy!=null){
			return ftStrategy.execute(ftDo);
		}else{
			throw new RuntimeException("Illegal fault tolerant type.");
		}
	}
	
	public ConcurrentHashMap<String, FtStrategy<REQ, RES>> getFtStrategyMap(){
		return ftStrategyMap;
	}
	
	public void addFtStrategy(String ftType, FtStrategy<REQ, RES> ftStrategy){
		ftStrategyMap.put(ftType, ftStrategy);
	}
	
	public void addFtStrategys(Map<String, FtStrategy<REQ, RES>> map){
		ftStrategyMap.putAll(map);
	}
	
	public void remove(String ftType){
		ftStrategyMap.remove(ftType);
	}
	
	public void clearAll(){
		ftStrategyMap.clear();
	}

}
